package com.shawn.baseappbygroovydsl.utils

import android.accessibilityservice.AccessibilityServiceInfo
import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.hardware.input.InputManager
import android.hardware.usb.UsbConstants
import android.hardware.usb.UsbManager
import android.os.BatteryManager
import android.os.Build
import android.provider.Settings
import android.telephony.TelephonyManager
import android.util.Base64
import android.view.accessibility.AccessibilityManager
import com.shawn.baseappbygroovydsl.ui.extension.ExtensionLog.log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
import java.io.IOException
import java.io.InputStreamReader
import java.net.InetAddress
import java.net.NetworkInterface
import java.util.Collections
import java.util.Enumeration
import java.util.Locale


/**
 * @author Secret
 * @since 2024/8/30
 */
object UtilScriptExplorer {

    fun test(context: Context) {
        """isAccessibilityRunning : ${isAccessibilityRunning(context)}\n +
                "isUSBConnect : ${isUSBConnected(context)}\n +
                "isInDevMode: ${isInDevMode(context)}\n +
                "isEmulator: ${isEmulator(context)}\n +
                "isRoot : ${isRoot(context)}""".log()
    }

    fun getLocalIpAddress(): String? {
        try {
            val interfaces: List<NetworkInterface> =
                Collections.list(NetworkInterface.getNetworkInterfaces())
            for (networkInterface in interfaces) {
                val inetAddresses: List<InetAddress> =
                    Collections.list(networkInterface.getInetAddresses())
                for (inetAddress in inetAddresses) {
                    // 检查是否为非回环地址且为本地地址
                    if (!inetAddress.isLoopbackAddress && inetAddress.isSiteLocalAddress) {
                        return inetAddress.hostAddress // 返回局域网IP地址
                    }
                }
            }
        } catch (ignored: Exception) {}
        return "" // 返回 null 表示没有找到局域网IP
    }

    fun retrieveInputDevices(context: Context):String {
        var res = ""
        val inputManager = context.getSystemService(Context.INPUT_SERVICE) as InputManager?
        val deviceIds = inputManager!!.inputDeviceIds
        for (deviceId in deviceIds) {
            val device = inputManager.getInputDevice(deviceId)
            if (device != null) {
                res+=",${device.name}:${device.sources}"
//                if(device.isVirtual){
//                    continue
//                }
//                // 检查设备是否为 HID 设备
//                if (device.sources and InputDevice.SOURCE_CLASS_BUTTON != 0 || device.sources and InputDevice.SOURCE_TOUCHSCREEN != 0 || device.sources and InputDevice.SOURCE_MOUSE != 0) {
//                    res+=",${device.name}"
//                }
            }
        }
        res.log("inputDevice:")
        return res
    }

    fun usbHidDevicesEnabled(context: Context): Boolean {
        val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager?
        val deviceList = usbManager!!.getDeviceList()
        for (device in deviceList.values) {
            // 检查是否是 HID 设备（通常 USB 类别为 0x03 表示 HID 设备）
            if (device.deviceClass == UsbConstants.USB_CLASS_HID) {
                return true
            }
            for (i in 0 until device.interfaceCount) {
                if (device.getInterface(i).interfaceClass == UsbConstants.USB_CLASS_HID) {
                    return true
                }
            }
        }
        return false
    }

    fun isVpnUsed(): Boolean {
        val networkInterfaces: Enumeration<NetworkInterface>?
        val iterator: Iterator<*>?
        try {
            networkInterfaces = NetworkInterface.getNetworkInterfaces()
            if (networkInterfaces == null) {
                return false
            }
            iterator = Collections.list(networkInterfaces).iterator()
            while (iterator.hasNext()) {
                val networkInterface = iterator.next()
                if (networkInterface != null && networkInterface.isUp() && networkInterface.getInterfaceAddresses().size != 0) {
                    if ("tun0" == networkInterface.name) {
                        return true
                    }
//                    if ("ppp0" != networkInterface.name) {
//                        break
//                    }
                }
            }
        } catch (ignored: Exception) {

        }
        return false
    }

    fun xposedExist(context: Context): Boolean {
        runCatching {
            return context.packageManager.getPackageInfo("de.robv.android.xposed.installer",
                0) != null
        }
        return false
    }

    fun isBTEnabled(context: Context):Boolean{
        runCatching {
            val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
            return bluetoothManager.adapter.isEnabled
        }
        return false
    }

    fun isAccessibilityRunning(context: Context): Boolean {
        runCatching {
            val accessibilityManager =
                context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
            return accessibilityManager.isEnabled
        }.onFailure {
            "isAccessibilityRunning $it".log()
        }
        return false
    }

    fun getEnabledAccService(context: Context):String{
        try {
            val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
            val enabledServiceList = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
            val valueSet = HashSet<String>()
            enabledServiceList.forEach {
                valueSet.add(it.resolveInfo.serviceInfo.packageName)
            }
            var res = ""
            valueSet.forEach {
                res += ",$it"
            }
            return toBase64(res)
        }catch (ignored:Exception){}
        return ""
    }

    fun isUSBConnected(context: Context): Boolean {
        runCatching {
//            val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
//            return usbManager.getDeviceList().size > 0
            val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
            val batteryStatus = context.registerReceiver(null, filter)
            val status = batteryStatus?.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) ?: -1
            return status == BatteryManager.BATTERY_PLUGGED_USB || status == BatteryManager.BATTERY_PLUGGED_AC || status == BatteryManager.BATTERY_PLUGGED_WIRELESS
        }.onFailure {
            "USB $it".log()
        }
        return false
    }

    fun isInDevMode(context: Context): Boolean {
        runCatching {
            val devMode: Int = Settings.Global.getInt(
                context.contentResolver,
                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED
            )
            return devMode == 1
        }
        return false
    }

    fun isInAdbMode(context: Context): Boolean {
        runCatching {
            val devMode: Int = Settings.Global.getInt(
                context.contentResolver,
                Settings.Global.ADB_ENABLED
            )
            return devMode == 1
        }
        return false
    }

    fun isEmulator(context: Context): Boolean {
        return EmulatorDetect.isEmulator(context)
    }

    fun isRoot(context: Context): Boolean {
        return RootDetect.isDeviceRooted(context)
    }

    suspend fun getInstallPkg(context: Context): String {
        return withContext(Dispatchers.IO) {
            val am = context.packageManager
            val pkgSet = HashSet<String>()
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                val intent = Intent(Intent.ACTION_MAIN)
                val installPkgs = am.queryIntentActivities(
                    intent,
                    PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong())
                )
                for (pkg in installPkgs) {
                    pkgSet.add(pkg.activityInfo.packageName)
                }
            } else {
                val installPkgs = am.getInstalledApplications(0)
                for (pkg in installPkgs) {
                    pkgSet.add(pkg.packageName)
                }
            }
            var infoValue = ""
            pkgSet.forEach {
                infoValue += ",$it"
            }
            toBase64(infoValue)
        }
    }

    private fun toBase64(str: String): String {
        val originalBytes = str.toByteArray()
        return Base64.encodeToString(originalBytes, Base64.DEFAULT)
    }

    object EmulatorDetect {

        private fun checkNetworkProperties(context: Context): Boolean {
            runCatching {
                val telephonyManager =
                    context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
                // 检查是否存在 SIM 卡
                val networkOperator = telephonyManager.networkOperatorName
                val phoneType = telephonyManager.getPhoneType()
                return "Android" == networkOperator || phoneType == TelephonyManager.PHONE_TYPE_NONE
            }
            return false
        }

        private fun checkFiles(): Boolean {
            val knownPaths = arrayOf(
                "/dev/socket/qemud",
                "/dev/qemu_pipe",
                "/system/lib/libc_malloc_debug_qemu.so",
                "/sys/qemu_trace",
                "/system/bin/qemu_props"
            )
            for (path in knownPaths) {
                val file = File(path)
                if (file.exists()) {
                    return true
                }
            }
            return false
        }

        private fun isEmulatorV1(): Boolean {
            // 检查设备型号、硬件、制造商等属性
            val model = Build.MODEL
            val product = Build.PRODUCT
            val manufacturer = Build.MANUFACTURER
            val brand = Build.BRAND
            val device = Build.DEVICE
            val hardware = Build.HARDWARE

            // 检测常见的模拟器标识
            return model.contains("Emulator") || model.contains("Android SDK") ||
                    product.contains("sdk") || product.contains("google_sdk") ||
                    manufacturer.contains("Genymotion") || brand.contains("generic") ||
                    device.contains("generic") || hardware.contains("goldfish") || hardware.contains(
                "ranchu"
            )
        }

        private fun isEmulatorV2(): Boolean {
            return try {
                if (!Build.FINGERPRINT.startsWith("generic") &&
                    !Build.FINGERPRINT.lowercase(Locale.getDefault()).contains("vbox") &&
                    !Build.FINGERPRINT.lowercase(Locale.getDefault())
                        .contains("test-keys") && !Build.MODEL.contains("google_sdk") && !Build.MODEL.contains(
                        "Emulator"
                    ) &&
                    !Build.MODEL.contains("Android SDK built for x86") &&
                    !Build.MANUFACTURER.contains("Genymotion") && (!Build.BRAND.startsWith("generic") || !Build.DEVICE.startsWith(
                        "generic"
                    ))
                ) {
                    if ("google_sdk" != Build.PRODUCT) {
                        return false
                    }
                }
                true
            } catch (e: java.lang.Exception) {
                false
            }
        }

        private fun getBaseBandVersion(): String {
            var baseBandVersion = ""
            var reader:BufferedReader? = null
            try {
                val process = Runtime.getRuntime().exec("getprop gsm.version.baseband")
                reader = BufferedReader(InputStreamReader(process.inputStream))
                baseBandVersion = reader.readLine()
                reader.close()
            } catch (ignored: Exception) {
            }finally {
                reader?.close()
            }
            return baseBandVersion
        }

        private fun hasBaseBand(): Boolean {
            val baseBand: String = getBaseBandVersion()
            baseBand.log("baseBand:")
            // 判断是否为空或未知，某些设备可能会返回"unknown"或空字符串表示没有基带
            return baseBand.isNotEmpty() && !"unknown".equals(
                baseBand,
                ignoreCase = true
            )
        }

        fun isEmulator(context: Context): Boolean {
            return isEmulatorV1() || checkNetworkProperties(context) || checkFiles() || isEmulatorV2() || !hasBaseBand()
        }

    }

    object RootDetect {
        private fun checkSuFile(): Boolean {
            val paths = arrayOf(
                "/system/app/Superuser.apk",
                "/system/bin/su",
                "/system/xbin/su",
                "/sbin/su",
                "/system/su",
                "/system/bin/.ext/.su",
                "/system/usr/we-need-root/su-backup",
                "/data/local/xbin/su",
                "/data/local/bin/su",
                "/data/local/su",
                "/su/bin/su",
                "/system/sd/xbin/su",
                "/system/bin/failsafe/su"
            )
            for (path in paths) {
                val file = File(path)
                if (file.exists()) {
                    return true
                }
            }
            return false
        }

        private fun checkRootMethod1(): Boolean {
            return try {
                val str = Build.TAGS
                str?.contains("test-keys") ?: false
            } catch (e: Exception) {
                false
            }
        }

        private fun checkRootBySuCommand(): Boolean {
            var process: Process? = null
            return try {
                // 执行 su 命令
                process = Runtime.getRuntime().exec(arrayOf("/system/xbin/which", "su"))
                val `in` = BufferedReader(InputStreamReader(process.inputStream))
                // su 命令成功执行，设备已 root
                `in`.readLine() != null
            } catch (e: Exception) {
                false // su 命令执行失败，设备未 root
            } finally {
                process?.destroy()
            }
        }

        private fun checkSystemWriteAccess(): Boolean {
            return try {
                val systemDir = File("/system")
                systemDir.canWrite()
            } catch (e: java.lang.Exception) {
                false
            }
        }

        private fun checkBuildProp(): Boolean {
            var br: BufferedReader? = null
            try {
                val file = File("/system/build.prop")
                br = BufferedReader(FileReader(file))
                var line: String
                while (br.readLine().also { line = it } != null) {
                    if (line.contains("ro.debuggable=1") || line.contains("ro.secure=0")) {
                        return true // 有异常属性，可能已 root
                    }
                }
            } catch (ignored: Exception) {
            } finally {
                br?.close()
            }
            return false
        }

        private fun checkRootManagementApps(context: Context): Boolean {
            val packages = arrayOf(
                "com.noshufou.android.su",
                "eu.chainfire.supersu",
                "com.koushikdutta.superuser",
                "com.thirdparty.superuser",
                "com.yellowes.su"
            )
            val pm: PackageManager = context.packageManager
            for (packageName in packages) {
                try {
                    pm.getPackageInfo(packageName, 0) // 如果能够找到这些包，说明可能已 root
                    return true
                } catch (e: PackageManager.NameNotFoundException) {
                    // 忽略异常
                }
            }
            return false
        }

        private fun checkRootMethod4(): Boolean {
            try {
                val process = Runtime.getRuntime().exec("mount")
                val reader = BufferedReader(InputStreamReader(process.inputStream))
                var line: String
                while (reader.readLine().also { line = it } != null) {
                    if (line.contains("/system")) {
                        // 检查/system分区是否以可写模式挂载
                        if (line.contains("rw")) {
                            return true // /system分区以可写模式挂载，设备已Root
                        }
                    }
                }
                reader.close()
            } catch (ignored: Exception) {

            }
            return false // /system分区未以可写模式挂载，设备未Root
        }


        fun isDeviceRooted(context: Context): Boolean {
            return checkSuFile() || checkRootBySuCommand() || checkSystemWriteAccess() || checkBuildProp() || checkRootMethod1() || checkRootMethod4() || BootLoaderDetect.isBootloaderUnlock()
        }

    }

    object BootLoaderDetect{

        fun isBootloaderUnlock():Boolean{
            return isBootloaderUnlocked1() || isBootloaderUnlocked2() || isBootloaderUnlocked3() || isBootloaderUnlocked4()
        }

        private fun isBootloaderUnlocked1(): Boolean {
            val bootloaderStatus = getSystemProperty("ro.boot.flash.locked")
            return "0" == bootloaderStatus // 0表示已解锁，1表示未解锁
        }

        private fun isBootloaderUnlocked2(): Boolean {
            // 首先检查是否支持解锁
            val unlockSupported = getSystemProperty("ro.oem_unlock_supported")
            if ("1" != unlockSupported) {
                return false // 不支持Bootloader解锁的设备
            }

            // 检查Bootloader是否已解锁
            val bootloaderStatus = getSystemProperty("ro.boot.flash.locked")
            return "0" == bootloaderStatus // 0表示已解锁，1表示未解锁
        }

        private fun isBootloaderUnlocked3(): Boolean {
            val bootloaderStatus = getSystemPropertyByReflection("ro.boot.flash.locked")
            return "0" == bootloaderStatus // 0表示已解锁，1表示未解锁
        }

        private fun isBootloaderUnlocked4(): Boolean {
            val cmdline = readCmdline()
            return cmdline.contains("androidboot.unlock=1") // 如果包含unlock=1，表示Bootloader已解锁
        }

        private fun getSystemProperty(property: String): String {
            var result = ""
            try {
                val process = Runtime.getRuntime().exec("getprop $property")
                val reader = BufferedReader(InputStreamReader(process.inputStream))
                result = reader.readLine()
                reader.close()
                process.waitFor()
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return result
        }

        private fun getSystemPropertyByReflection(key: String): String {
            var value = ""
            try {
                val clazz = Class.forName("android.os.SystemProperties")
                val method = clazz.getDeclaredMethod("get", String::class.java)
                value = method.invoke(null, key) as String
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return value
        }

        private fun readCmdline(): String {
            val cmdline = StringBuilder()
            try {
                val reader = BufferedReader(FileReader("/proc/cmdline"))
                var line: String?
                while (reader.readLine().also { line = it } != null) {
                    cmdline.append(line)
                }
                reader.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
            return cmdline.toString()
        }

    }

}